Skip to content

fix(sync): notification can get stuck. - #20363

Merged
david-allison merged 1 commit into
ankidroid:mainfrom
Giyutomioka-SS:stuck-sync-notification-19830
Mar 26, 2026
Merged

fix(sync): notification can get stuck.#20363
david-allison merged 1 commit into
ankidroid:mainfrom
Giyutomioka-SS:stuck-sync-notification-19830

Conversation

@Giyutomioka-SS

@Giyutomioka-SS Giyutomioka-SS commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Purpose / Description

This change makes sure the sync notifications (“Syncing…” and “Syncing media…”) are always removed, even when sync is cancelled or fails with an error. Previously they were only cleared on a clean, successful sync, so in rare cases they could stay stuck for a long time.

Fixes

Approach

When the main sync worker and the media sync worker finish, we now always call notificationManager.cancel(...) from a finally block. This runs no matter how the work ends: success, error, or when the user presses the Cancel button on the notification, so the ongoing sync notifications are reliably dismissed.

How Has This Been Tested?

Verified that both sync workers now always cancel their notifications from a finally block on all exit paths (success, error, and user cancel), and that the project builds and ktlint passes locally.

but i haven’t been able to reliably reproduce the original stuck-notification issue, so I’d really appreciate it if someone who has seen it could help confirm the fix end to end, or share the exact steps to reproduce it.

Related:

Checklist

Please, go through these checks before submitting the PR.

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

@criticalAY criticalAY left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logically seems correct to me but can you add tests to verify this, add tests to see if you can reproduce the error there and your solution later should pass the tests.

@criticalAY criticalAY added Needs Author Reply Waiting for a reply from the original author and removed Needs Review labels Feb 27, 2026
@Giyutomioka-SS

Giyutomioka-SS commented Feb 27, 2026

Copy link
Copy Markdown
Contributor Author

Logically seems correct to me but can you add tests to verify this, add tests to see if you can reproduce the error there and your solution later should pass the tests.

Added Robolectric test for SyncMediaWorker that simulates an error after the foreground notification is active and verifies the notification is always cancelled from the finally block.

@lukstbit lukstbit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we encounter an error in the workers we are currently showing a notification but your code would immediately cancel this notification.

I'm also less inclined to accept a fix if there's no reproduction case.

@Giyutomioka-SS

Copy link
Copy Markdown
Contributor Author

When we encounter an error in the workers we are currently showing a notification but your code would immediately cancel this notification.

I'm also less inclined to accept a fix if there's no reproduction case.

To avoid the error notification being cancelled, can we use separate notification IDs for failed cases so the finally block only cancels the progress notification?? @lukstbit

I’ve tried multiple times to reproduce the original stuck-notification bug, but I haven’t been able to so far. The added test covers the same scenario (error after the notification is shown) and it passes with the fix, i'll keep testing on a real device and if I’m able to reproduce it i'll share a video here.

@lukstbit lukstbit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think different notifications ids would fix this, feels something related to the WorkManager system itself when the worker is cancelled(maybe due to the constraint). I propose to just add a call to notificationManager?.cancel(NotificationId.SYNC_MEDIA) just before the cancelMediaSync(CollectionManager.getBackend()) line in the catch that deals with the coroutine cancellation and see how this goes in production.

The test should be removed, it mocks so much that it isn't real life behavior.

@Giyutomioka-SS

Copy link
Copy Markdown
Contributor Author

I don't think different notifications ids would fix this, feels something related to the WorkManager system itself when the worker is cancelled(maybe due to the constraint). I propose to just add a call to notificationManager?.cancel(NotificationId.SYNC_MEDIA) just before the cancelMediaSync(CollectionManager.getBackend()) line in the catch that deals with the coroutine cancellation and see how this goes in production.

The test should be removed, it mocks so much that it isn't real life behavior.

Got it, thanks for the explanation and suggestion.

@david-allison
david-allison marked this pull request as draft March 3, 2026 20:42
@david-allison

Copy link
Copy Markdown
Member

It'd be great to see this fixed!

Drafting this until it's ready.

Please mark it as ready for review once a reproduction case is found (even if this is just a patch to the code).


In addition:

  • Consider more logging if it's currently insufficient.
  • Figure out why 'cancel'/swiping the notification wasn't working, and potentially also fix this failure case.

@Giyutomioka-SS

Giyutomioka-SS commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

It'd be great to see this fixed!

Drafting this until it's ready.

Please mark it as ready for review once a reproduction case is found (even if this is just a patch to the code).

In addition:

  • Consider more logging if it's currently insufficient.
  • Figure out why 'cancel'/swiping the notification wasn't working, and potentially also fix this failure case.

@david-allison, I still haven’t been able to reproduce the stuck-notification behavior naturally on my device, but the stuck notification is likely caused by WorkManager cancelling the sync worker due to constraints, as lukstbit mentioned also. (network drop, battery saver, OEM killing the app etc.)

When this happens, the worker throws a CancellationException. We abort the backend sync, but earlier we did not cancel the sync notification in that flow. As a result, the ongoing “Syncing…” notification could remain visible and could not be swiped away.

The fix adds an explicit notificationManager.cancel(NotificationId.SYNC / SYNC_MEDIA) inside the CancellationException handler, so when WorkManager cancels the job, the progress notification is properly cleared instead of getting stuck.

@Giyutomioka-SS
Giyutomioka-SS requested a review from lukstbit March 9, 2026 19:49
@Giyutomioka-SS
Giyutomioka-SS marked this pull request as ready for review March 9, 2026 19:56
@github-actions

Copy link
Copy Markdown
Contributor

Hello 👋, this PR has had no activity for more than 2 weeks and needs a reply from the author. If you think this is a mistake please comment and ping a maintainer to get this merged ASAP! Thanks for contributing! You have 7 days until this gets closed automatically

@github-actions github-actions Bot added the Stale label Mar 23, 2026

@lukstbit lukstbit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.
The cancellation of the worker is the only path we don't cover for notification handling so I think it's worth to add the code for logging and as an attempt of the fix.

@lukstbit lukstbit added Needs Second Approval Has one approval, one more approval to merge Needs reviewer reply Waiting for a reply from another reviewer and removed Needs Author Reply Waiting for a reply from the original author Stale labels Mar 24, 2026
@david-allison
david-allison force-pushed the stuck-sync-notification-19830 branch from 14d78a1 to f5a8a3a Compare March 24, 2026 14:59
@david-allison david-allison added Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) and removed Needs Second Approval Has one approval, one more approval to merge Needs reviewer reply Waiting for a reply from another reviewer labels Mar 24, 2026
@david-allison
david-allison enabled auto-merge March 24, 2026 14:59
@david-allison

Copy link
Copy Markdown
Member

thanks so much!!

@lukstbit

Copy link
Copy Markdown
Member

@david-allison The test you added is failing and it doesn't look right, you're throwing an exception on a method that is called before the call you are checking for.

@david-allison

Copy link
Copy Markdown
Member

The test should be removed, it mocks so much that it isn't real life behavior.

@lukstbit I believe I re-added the test in my force push (given the above message), apologies. If this isn't the same test, please flag it, I do not recall writing it.

@david-allison
david-allison force-pushed the stuck-sync-notification-19830 branch from f5a8a3a to 6216763 Compare March 26, 2026 21:26
@david-allison
david-allison added this pull request to the merge queue Mar 26, 2026
Merged via the queue into ankidroid:main with commit cab77b7 Mar 26, 2026
15 checks passed
@github-actions github-actions Bot added this to the 2.24 release milestone Mar 26, 2026
@github-actions github-actions Bot removed the Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) label Mar 26, 2026
@LUwUcifer

Copy link
Copy Markdown
Contributor

@Giyutomioka-SS can you clarify which parts of the issue this pr doesn't solve? or should #19830 be marked as fixed?

@Giyutomioka-SS

Copy link
Copy Markdown
Contributor Author

@LUwUcifer, this PR covers the normal sync completion/error paths but doesn’t fully handle the WorkManager worker cancellation path yet, so that’s where the notification could still get stuck.

I couldn’t reproduce this, could you try and see if it happens on your side?
If yes, please share the steps, device/Android version, and logs here.

@LUwUcifer

Copy link
Copy Markdown
Contributor

Nope, should add "can't reproduce" tag to #19830

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants